#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44

int lastcode = 0;
int quit = 0;
extern char** environ;
char commandline[LINE_SIZE];
char* argv[ARGC_SIZE];
char pwd[LINE_SIZE];
char myenv[LINE_SIZE];
const char* Getusername()
{
    return getenv("USER");
}

const char* Gethostname()
{
    return getenv("HOSTNAME");
}

void Getpwd()
{
    getcwd(pwd,sizeof(pwd));
}

void interact(char* cline, int size)
{
    Getpwd();
    printf(LEFT"%s@%s %s"RIGHT""LABLE" ",Getusername(),Gethostname(),pwd);
    char *s = fgets(cline,size,stdin);//输入命令
    assert(s);//断言fgets有没有出错
    (void)s;//为了没有警告
    cline[strlen(cline)-1] = '\0';//为了将输入命令的回车符去掉
}

int splitstring(char* cline, char* argv[])
{
    int i = 0;
    argv[i++] = strtok(cline,DELIM);
    while(argv[i++] = strtok(NULL,DELIM));
    return i - 1;
} 

void NormalExcute(char* argv[])
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return;
    }
    else if(id == 0)
    {
        //让子进程执行命令
        execvp(argv[0],argv);
    }
    else 
    {
        int status = 0;
        pid_t rid = waitpid(id,&status,0);
        if(rid == id)
        {
            lastcode = WEXITSTATUS(status);
        }
    }
}

int buildCommand(int argc, char* argv[])
{
    if(argc == 2 && strcmp(argv[0],"cd") == 0)
    {
        chdir(argv[1]);
        Getpwd();
        sprintf(getenv("PWD"), "%s", pwd);
        return 1;
    }
    else if(argc == 2 && strcmp(argv[0],"export") == 0)
    {
        strcpy(myenv,argv[1]);
        putenv(myenv);
        return 1;
    }
    else if(argc == 2 && strcmp(argv[0],"echo") == 0)
    {
        if(*argv[1] == '$')
        {
            char* val = getenv(argv[1] + 1);
            if(val) printf("%s\n", val);
        }
        else 
        {
            printf("%s\n",argv[1]);
        }
        return 1;
    }

    //特殊处理ls，使它有颜色
    if(strcmp(argv[0],"ls") == 0)
    {
        argv[argc++] = "--color";
        argv[argc++] = NULL;
    }

    return 0;
}

int main()
{
    while(!quit)
    {
        //交互问题，获取命令行
        interact(commandline,sizeof(commandline));

        //子串分割的问题，解析命令行
        int argc = splitstring(commandline,argv);
        if(argc == 0) continue;
        
        //内建命令
        int n = buildCommand(argc,argv);        

        //普通命令的执行
        if(!n) NormalExcute(argv);
    }
    return 0;
}
